package common

import (
	"fmt"
	"strconv"
	"strings"
	"time"
)

// 涵盖了常用的时间操作  不处理/的情况 ,如果需要需要先转换为-格式在使用
//将/转换为-格式
//date = strings.Replace(date, "/", "-", -1)

type TimeUnit string //时间单位
const (
	Nanosecond  TimeUnit = "ns" //纳秒 1秒=1000000000纳秒
	UnixMicro   TimeUnit = "us" //微秒  1秒=1000000微秒
	MILLISECOND TimeUnit = "ms" //毫秒  1秒=1000毫秒
	SECOND      TimeUnit = "s"  //秒
	MINUTE      TimeUnit = "m"  //分
	HOUR        TimeUnit = "h"  //时
	DAY         TimeUnit = "d"  //天
	WEEK        TimeUnit = "w"  //周
	MONTH       TimeUnit = "M"  //月
	YEAR        TimeUnit = "y"  //年
)

type DateSeparatorType string

const (
	DATE_SEPARATOR  DateSeparatorType = "-" //日期分隔符
	DATE_SEPARATOR2 DateSeparatorType = "/" //日期分隔符
)

type DateFormatType string

const (
	YYYY_MM_DD_HH_MM_SS_SSS DateFormatType = "2006-01-02 15:04:05.000" //年月日时分秒毫秒
	YYYY_MM_DD_HH_MM_SS     DateFormatType = "2006-01-02 15:04:05"     //年月日时分秒
	YYYY_MM_DD_HH_MM        DateFormatType = "2006-01-02 15:04"        //年月日时分
	YYYY_MM_DD_HH           DateFormatType = "2006-01-02 15"           //年月日时
	YYYY_MM_DD              DateFormatType = "2006-01-02"              //年月日
	YYYY_MM                 DateFormatType = "2006-01"                 //年月

	MM_DD_HH_MM_SS DateFormatType = "01-02 15:04:05" //月日时分秒
	MM_DD_HH_MM    DateFormatType = "01-02 15:04"    //月日时分
	MM_DD_HH       DateFormatType = "01-02 15"       //月日时
	MM_SS          DateFormatType = "01:02"          //月分
	MM_DD          DateFormatType = "01-02"          //月日

	DD_HH_MM_SS DateFormatType = "02 15:04:05" //日时分秒
	DD_HH_MM    DateFormatType = "02 15:04"    //日时分
	DD_HH       DateFormatType = "02 15"       //日时

	HH_MM_SS_SSS DateFormatType = "15:04:05.000" //时分秒毫秒
	HH_MM_SS     DateFormatType = "15:04:05"     //时分秒
	HH_MM        DateFormatType = "15:04"        //时分

	YYYYMMDDHHMMSS DateFormatType = "20060102150405" //年月日时分秒
	YYYYMMDDHHMM   DateFormatType = "200601021504"   //年月日时分
	YYYYMMDDHH     DateFormatType = "2006010215"     //年月日时
	YYYYMMDD       DateFormatType = "20060102"       //年月日
	YYYYMM         DateFormatType = "200601"         //年月

	YYYY DateFormatType = "2006" //年
	MM   DateFormatType = "01"   //月
	DD   DateFormatType = "02"   //日
	HH   DateFormatType = "15"   //时
	mm   DateFormatType = "04"   //分
	SS   DateFormatType = "05"   //秒
	SSS  DateFormatType = "000"  //毫秒
)

type Weekday int

const (
	Monday    Weekday = 1
	Tuesday   Weekday = 2
	Wednesday Weekday = 3
	Thursday  Weekday = 4
	Friday    Weekday = 5
	Saturday  Weekday = 6
	Sunday    Weekday = 7
)

func (d Weekday) String() string {
	//转换为中文
	switch d {
	case Monday:
		return "星期一"
	case Tuesday:
		return "星期二"
	case Wednesday:
		return "星期三"
	case Thursday:
		return "星期四"
	case Friday:
		return "星期五"
	case Saturday:
		return "星期六"
	case Sunday:
		return "星期日"
	}
	panic(fmt.Sprintf("Weekday时间格式有误,date:%d", d))
}

// 转换的时间是time.Weekday 0-6
func toUsaWeek(week Weekday) time.Weekday {
	switch week {
	case Sunday:
		return time.Sunday
	case Monday:
		return time.Monday
	case Tuesday:
		return time.Tuesday
	case Wednesday:
		return time.Wednesday
	case Thursday:
		return time.Thursday
	case Friday:
		return time.Friday
	case Saturday:
		return time.Saturday
	default:
		panic(fmt.Sprintf("星期数有误:%d", week))
	}
}
func toChinaWeek(week time.Weekday) Weekday {
	switch week {
	case time.Sunday:
		return Sunday
	case time.Monday:
		return Monday
	case time.Tuesday:
		return Tuesday
	case time.Wednesday:
		return Wednesday
	case time.Thursday:
		return Thursday
	case time.Friday:
		return Friday
	case time.Saturday:
		return Saturday
	default:
		panic(fmt.Sprintf("星期数有误:%d", week))
	}

}

// 根据date 识别DateFormatType
// 只是获取常规的时间格式
// 1. yyyy-MM-dd HH:mm:ss.SSS
// 2. yyyy-MM-dd HH:mm:ss
// 3. yyyy-MM-dd
// 4. HH:mm:ss.SSS
// 5. HH:mm:ss
// 6. yyyyMMddHHmmss
// 7. yyyyMMddHHmm
// 8. yyyyMMdd
// 9. yyyyMM
func GetDateFormatType(date string) DateFormatType {
	//判断是-
	if strings.Contains(date, "-") {
		//判断是:
		if strings.Contains(date, ":") {
			//判断是.
			if strings.Contains(date, ".") {
				return YYYY_MM_DD_HH_MM_SS_SSS
			}
			return YYYY_MM_DD_HH_MM_SS
		}
		return YYYY_MM_DD

	} else if strings.Contains(date, ":") {
		//判断是.
		if strings.Contains(date, ".") {
			return HH_MM_SS_SSS
		}
		return HH_MM_SS
	} else {
		//长度判断
		if len(date) == 14 {
			return YYYYMMDDHHMMSS
		} else if len(date) == 12 {
			return YYYYMMDDHHMM
		} else if len(date) == 10 {
			return YYYYMMDD
		} else if len(date) == 8 {
			return YYYYMM
		} else if len(date) == 6 {
			return YYYYMM
		}
	}
	panic(fmt.Sprintf("GetDateFormatType时间格式有误,date:%s", date))
}

// 返回枚举的值
func (d DateFormatType) String() string {
	return string(d)
}

// 获取时间戳
func Now(timeUnit TimeUnit) int64 {
	if timeUnit == Nanosecond {
		return time.Now().UnixNano()
	} else if timeUnit == UnixMicro {
		return time.Now().UnixMicro()
	} else if timeUnit == MILLISECOND {
		return time.Now().UnixMilli()
	} else if timeUnit == SECOND {
		return time.Now().Unix()
	} else if timeUnit == MINUTE {
		return time.Now().Unix() / 60
	} else if timeUnit == HOUR {
		return time.Now().Unix() / 3600
	} else if timeUnit == DAY {
		return time.Now().Unix() / 86400
	} else if timeUnit == WEEK {
		return time.Now().Unix() / 604800
	} else if timeUnit == MONTH {
		return time.Now().Unix() / 2592000
	} else if timeUnit == YEAR {
		return time.Now().Unix() / 31536000
	}
	panic("时间戳转换失败")
}

// 将字符串转换为时间戳秒
func Parse(str string, format DateFormatType, timeUnit TimeUnit) int64 {
	if str != "" {
		parse, err := time.ParseInLocation(format.String(), str, time.Local)
		if err != nil {
			panic(err.Error())
		}
		if timeUnit == Nanosecond {
			return parse.UnixNano()
		} else if timeUnit == UnixMicro {
			return parse.UnixMicro()
		} else if timeUnit == MILLISECOND {
			return parse.UnixMilli()
		} else if timeUnit == SECOND {
			return parse.Unix()
		} else if timeUnit == MINUTE {
			return parse.Unix() / 60
		} else if timeUnit == HOUR {
			return parse.Unix() / 3600
		} else if timeUnit == DAY {
			return parse.Unix() / 86400
		} else if timeUnit == WEEK {
			return parse.Unix() / 604800
		} else if timeUnit == MONTH {
			return parse.Unix() / 2592000
		} else if timeUnit == YEAR {
			return parse.Unix() / 31536000
		}

	}
	panic(str + "时间转换失败")
}

// 获取当前年月日时分秒
func NowPart() (int, int, int, int, int, int) {
	now := time.Now()
	return now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Second()
}

// 只获取当前年月日
func NowPartDate() (int, int, int) {
	now := time.Now()
	return now.Year(), int(now.Month()), now.Day()
}

// 只获取当前时分秒
func NowPartTime() (int, int, int) {
	now := time.Now()
	return now.Hour(), now.Minute(), now.Second()
}

// 获取当前年月日,指定时分秒
func AtDayTime(hour int, mm int, ss int) string {
	//获取当前时间
	now := time.Now()
	//设置时间
	now = time.Date(now.Year(), now.Month(), now.Day(), hour, mm, ss, 0, time.Local)
	return now.Format(YYYY_MM_DD_HH_MM_SS.String())
}

// 时间戳转换为字符串
func Format(timestamp int64, format DateFormatType) string {
	//转字符串
	timestampStr := strconv.FormatInt(timestamp, 10)
	if timestampStr != "" && format != "" && len(timestampStr) >= 10 {
		timestampStr = timestampStr[:10]
		i, err := strconv.ParseInt(timestampStr, 10, 64)
		if err == nil {
			//将yyyy-MM-dd HH:mm:ss.SSS转换为go的时间格式2006-01-02 15:04:05.000
			var formatStr = strings.Replace(format.String(), "yyyy", "2006", -1)
			formatStr = strings.Replace(formatStr, "MM", "01", -1)
			formatStr = strings.Replace(formatStr, "dd", "02", -1)
			formatStr = strings.Replace(formatStr, "HH", "15", -1)
			formatStr = strings.Replace(formatStr, "mm", "04", -1)
			formatStr = strings.Replace(formatStr, "ss", "05", -1)
			formatStr = strings.Replace(formatStr, "SSS", "000", -1)
			return time.Unix(i, 0).Format(formatStr)
		}
	}
	panic(fmt.Sprintf("时间戳转换失败,timestamp:%s,format:%s", timestampStr, format))
}

// 获取年-月-日 时:分:秒
func NowStr(format DateFormatType) string {
	return time.Now().Format(format.String())
}
func NowDateTimeStr() string {
	return time.Now().Format(YYYY_MM_DD_HH_MM_SS.String())
}

// 时间比较 (字符串格式时间比较,类型必须一致)
// 1: 表示time1>time2
// -1: 表示time1<time2
// 0: 表示time1=time2
func EqTime(time1 string, time2 string, format DateFormatType) int {
	//判断长度是否一致
	if len(time1) != len(time2) {
		panic(fmt.Sprintf("时间比较失败格式不一致,time1:%s,time2:%s", time1, time2))
	}
	if time1 != "" && time2 != "" {
		t1 := Parse(time1, format, SECOND)
		t2 := Parse(time2, format, SECOND)
		if t1 > t2 {
			return 1
		} else if t1 < t2 {
			return -1
		} else {
			return 0
		}
	}
	panic(fmt.Sprintf("时间比较失败,time1:%s,time2:%s", time1, time2))
}

// 拆解时间为年月日时分秒毫秒 ,格式必须是yyyy-MM-dd HH:mm:ss.SSS
func SplitTime(dateTime string) (int, int, int, int, int, int, int) {
	if dateTime != "" && len(dateTime) >= 19 && strings.Contains(dateTime, "-") && strings.Contains(dateTime, ":") {
		year, _ := strconv.Atoi(dateTime[:4])
		month, _ := strconv.Atoi(dateTime[5:7])
		day, _ := strconv.Atoi(dateTime[8:10])
		hour, _ := strconv.Atoi(dateTime[11:13])
		minute, _ := strconv.Atoi(dateTime[14:16])
		second, _ := strconv.Atoi(dateTime[17:19])
		//判断是否有毫秒
		if len(dateTime) == 19 {
			return year, month, day, hour, minute, second, 0
		}
		millisecond, _ := strconv.Atoi(dateTime[20:23])
		return year, month, day, hour, minute, second, millisecond
	}
	panic(fmt.Sprintf("时间拆解失败长度最低为19格式为yyyy-MM-dd HH:mm:ss而你的是:%s", dateTime))

}

// 一个时间减去一个时间单位
func StrSubTime(time1 string, format DateFormatType, num int, timeUnit TimeUnit) string {
	if time1 != "" {
		year, i, i2, i3, i4, i5, i6 := SplitTime(time1)
		date := time.Date(year, time.Month(i), i2, i3, i4, i5, i6, time.Local)
		if timeUnit == Nanosecond {
			date = date.Add(-time.Duration(num))
		} else if timeUnit == UnixMicro {
			date = date.Add(-time.Duration(num) * time.Microsecond)
		} else if timeUnit == MILLISECOND {
			date = date.Add(-time.Duration(num) * time.Millisecond)
		} else if timeUnit == SECOND {
			date = date.Add(-time.Duration(num) * time.Second)
		} else if timeUnit == MINUTE {
			date = date.Add(-time.Duration(num) * time.Minute)
		} else if timeUnit == HOUR {
			date = date.Add(-time.Duration(num) * time.Hour)
		} else if timeUnit == DAY {
			date = date.AddDate(0, 0, -num)
		} else if timeUnit == WEEK {
			date = date.AddDate(0, 0, -num*7)
		} else if timeUnit == MONTH {
			date = date.AddDate(0, -num, 0)
		} else if timeUnit == YEAR {
			date = date.AddDate(-num, 0, 0)
		}
		return date.Format(format.String())
	}
	panic(fmt.Sprintf("时间减失败,time1:%s", time1))
}

// 时间戳减去一个时间单位
func SubTime(timestamp int64, num int, timeUnit TimeUnit) int64 {
	if timeUnit == Nanosecond {
		return timestamp - int64(num)
	} else if timeUnit == UnixMicro {
		return timestamp - int64(num)*1000
	} else if timeUnit == MILLISECOND {
		return timestamp - int64(num)*1000
	} else if timeUnit == SECOND {
		return timestamp - int64(num)
	} else if timeUnit == MINUTE {
		return timestamp - int64(num)*60
	} else if timeUnit == HOUR {
		return timestamp - int64(num)*3600
	} else if timeUnit == DAY {
		return timestamp - int64(num)*86400
	} else if timeUnit == WEEK {
		return timestamp - int64(num)*604800
	} else if timeUnit == MONTH {
		return timestamp - int64(num)*2592000
	} else if timeUnit == YEAR {
		return timestamp - int64(num)*31536000
	}
	panic(fmt.Sprintf("时间减失败,timestamp:%d", timestamp))
}

// 一个时间加上一个时间单位
func StrAddTime(time1 string, format DateFormatType, num int, timeUnit TimeUnit) string {
	if time1 != "" {
		year, i, i2, i3, i4, i5, i6 := SplitTime(time1)
		date := time.Date(year, time.Month(i), i2, i3, i4, i5, i6, time.Local)
		if timeUnit == Nanosecond {
			date = date.Add(time.Duration(num))
		} else if timeUnit == UnixMicro {
			date = date.Add(time.Duration(num) * time.Microsecond)
		} else if timeUnit == MILLISECOND {
			date = date.Add(time.Duration(num) * time.Millisecond)
		} else if timeUnit == SECOND {
			date = date.Add(time.Duration(num) * time.Second)
		} else if timeUnit == MINUTE {
			date = date.Add(time.Duration(num) * time.Minute)
		} else if timeUnit == HOUR {
			date = date.Add(time.Duration(num) * time.Hour)
		} else if timeUnit == DAY {
			date = date.AddDate(0, 0, num)
		} else if timeUnit == WEEK {
			date = date.AddDate(0, 0, num*7)
		} else if timeUnit == MONTH {
			date = date.AddDate(0, num, 0)
		} else if timeUnit == YEAR {
			date = date.AddDate(num, 0, 0)
		}
		return date.Format(format.String())

	}
	panic(fmt.Sprintf("时间加失败,time1:%s", time1))
}

// 时间戳加上一个时间单位
func AddTime(timestamp int64, num int, timeUnit TimeUnit) int64 {
	if timeUnit == Nanosecond {
		return timestamp + int64(num)
	} else if timeUnit == UnixMicro {
		return timestamp + int64(num)*1000
	} else if timeUnit == MILLISECOND {
		return timestamp + int64(num)*1000
	} else if timeUnit == SECOND {
		return timestamp + int64(num)
	} else if timeUnit == MINUTE {
		return timestamp + int64(num)*60
	} else if timeUnit == HOUR {
		return timestamp + int64(num)*3600
	} else if timeUnit == DAY {
		return timestamp + int64(num)*86400
	} else if timeUnit == WEEK {
		return timestamp + int64(num)*604800
	} else if timeUnit == MONTH {
		return timestamp + int64(num)*2592000
	} else if timeUnit == YEAR {
		return timestamp + int64(num)*31536000
	}
	panic(fmt.Sprintf("时间加失败,timestamp:%d", timestamp))
}

// 一个时间字符串减去另一个时间字符串相差多少 年月日时分秒
func StrSubStr(time1 string, time2 string, format DateFormatType) (int, int, int, int, int, int) {
	if time1 != "" && time2 != "" && len(time1) == len(time2) {
		t1 := Parse(time1, format, SECOND)
		t2 := Parse(time2, format, SECOND)
		sub := t1 - t2
		year := sub / 31536000
		month := sub / 2592000
		day := sub / 86400
		hour := sub / 3600
		minute := sub / 60
		second := sub
		return int(year), int(month), int(day), int(hour), int(minute), int(second)
	}
	panic(fmt.Sprintf("时间相减失败,time1:%s,time2:%s", time1, time2))

}

// 获取本周六和周日的日期(是依据当前时间计算的)
func GetWeekend(hour int, mm int, ss int) (string, string) {
	//获取当前时间
	now := time.Now()
	//获取今天是周几
	weekday := now.Weekday()
	//获取周六的时间
	saturday := now.AddDate(0, 0, 6-int(weekday))
	//获取周日的时间
	sunday := now.AddDate(0, 0, 7-int(weekday))
	//设置时间
	saturday = time.Date(saturday.Year(), saturday.Month(), saturday.Day(), hour, mm, ss, 0, time.Local)
	sunday = time.Date(sunday.Year(), sunday.Month(), sunday.Day(), hour, mm, ss, 0, time.Local)
	return saturday.Format(YYYY_MM_DD_HH_MM_SS.String()), sunday.Format(YYYY_MM_DD_HH_MM_SS.String())
}

// 判断当前时间是否在指定时间范围内 ,不包含等于
func NowScopeTime(start string, end string, format DateFormatType) bool {
	now := time.Now().Format(format.String())
	if EqTime(now, start, format) == 1 && EqTime(now, end, format) == -1 {
		return true
	}
	return false
}

// 获取第二天几分几秒的时间
func GetNextDayTime(hour int, mm int, ss int) string {
	//获取当前时间
	now := time.Now()
	//获取明天的时间
	next := now.AddDate(0, 0, 1)
	//设置时间
	next = time.Date(next.Year(), next.Month(), next.Day(), hour, mm, ss, 0, time.Local)
	return next.Format(YYYY_MM_DD_HH_MM_SS.String())
}

// 获取本周几的时间
func GetWeekTime(week Weekday, hour int, mm int, ss int) string {
	///判断输入的星期数是否正确
	if week < 1 || week > 7 {
		panic(fmt.Sprintf("星期数有误:%d", week))
	}
	now := time.Now()
	//获取当前是星期几
	w := now.Weekday()
	chinaWeek := toChinaWeek(w)
	tarWeek := week - chinaWeek

	//距离星期7差几天就加几天
	now = now.AddDate(0, 0, int(tarWeek))

	//设置时分秒
	now = time.Date(now.Year(), now.Month(), now.Day(), hour, mm, ss, 0, time.Local)
	return now.Format(YYYY_MM_DD_HH_MM_SS.String())
}

// 获取下周几的时间
func GetNextWeekTime(week Weekday, hour int, mm int, ss int) string {
	///判断输入的星期数是否正确
	if week < 1 || week > 7 {
		panic(fmt.Sprintf("星期数有误:%d", week))
	}
	now := time.Now()
	//获取当前是星期几
	w := now.Weekday()
	chinaWeek := toChinaWeek(w)
	tarWeek := 7 - chinaWeek
	//先补齐本周然后加上下周的时间
	now = now.AddDate(0, 0, int(tarWeek+week))
	//设置时间
	now = time.Date(now.Year(), now.Month(), now.Day(), hour, mm, ss, 0, time.Local)
	return now.Format(YYYY_MM_DD_HH_MM_SS.String())
}
